namespace ClassyBlog.Specs.Acceptance
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Reflection;
    using System.Threading;
    using System.Web.Mvc;

    using TechTalk.SpecFlow;

    using Infrastructure;

    [Binding]
    public class Bootstrapper
    {
        public const int ServerPort = 6060;

        private static string applicationPath;
        private static Process webServer;

        [BeforeTestRun]
        public static void RunWebServer()
        {
            const string SpecProjectName = "ClassyBlog.Specs.Acceptance";
            const string Tools = "tools";

            var currentPath = Environment.CurrentDirectory;
            string solutionRoot;

            if (currentPath.Contains(SpecProjectName))
            {
                solutionRoot = currentPath.Substring(
                    0, currentPath.IndexOf(SpecProjectName));
            }
            else if (currentPath.Contains(Tools))
            {
                solutionRoot = currentPath.Substring(
                    0, currentPath.IndexOf(Tools));
            }
            else
            {
                throw new InvalidOperationException(
                    "Cannot run acceptance specs from unknown location.");
            }

            applicationPath = Path.Combine(solutionRoot, "ClassyBlog.Web");

            var webServerPath = Path.Combine(
                solutionRoot, Tools, "webserver", "WebDev.WebServer40.EXE");

            var arguments = string.Format(
                "/port:{0} /path:\"{1}\"",
                ServerPort,
                applicationPath);

            webServer = new Process
            {
                StartInfo =
                {
                    FileName = webServerPath,
                    Arguments = arguments,
                    WindowStyle = ProcessWindowStyle.Hidden,
                    ErrorDialog = false
                }
            };

            webServer.Start();
            Thread.Sleep(TimeSpan.FromSeconds(5));
        }

        [BeforeTestRun]
        public static void RegisterContainer()
        {
            var dataDirectory = Path.Combine(applicationPath, "App_Data");
            var container = new ServiceContainer();

            new ServiceRegistrations(dataDirectory, container).Register();
            container.RegisterAsSingleton<IBuildManager>(
                c => new TestEnvironmenBuildManager());

            DependencyResolver.SetResolver(
                new DefaultDependencyResolver(container));
        }

        [AfterTestRun]
        public static void StopWebServer()
        {
            if (webServer == null)
            {
                return;
            }

            webServer.Kill();
            webServer.Dispose();
        }

        private sealed class TestEnvironmenBuildManager : DefaultBuildManager
        {
            public override IEnumerable<Assembly> PrivateAssemblies
            {
                get
                {
                    return new[]
                               {
                                   typeof(Disposable).Assembly,
                                   typeof(DefaultBuildManager).Assembly
                               };
                }
            }
        }
    }
}